package com.java.oauth.service.impl;

import cn.hutool.core.util.StrUtil;
import com.java.common.exception.RRException;
import com.java.oauth.service.AuthService;
import com.java.oauth.util.AuthToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Map;

@Service
public class AuthServiceImpl implements AuthService {
	@Autowired
	private LoadBalancerClient loadBalancerClient;
	@Autowired
	private RestTemplate restTemplate;

	// 客户端id
	@Value("${auth.clientId}")
	private String clientId;
	// 客户端密码
	@Value("${auth.clientSecret}")
	private String clientSecret;
	// 微服务名称
	@Value("${spring.application.name}")
	private String appName;

	// 定义授权方式(密码授权)
	private static final String GRANT_TYPE = "password";

	/***
	 * 授权认证方法
	 */
	@Override
	public AuthToken login(String username, String password) {
		//申请令牌
		AuthToken authToken = applyToken(username, password, clientId, clientSecret);
		if (authToken == null) {
			throw new RRException("申请令牌失败");
		}
		return authToken;
	}


	/****
	 * 认证方法
	 */
	private AuthToken applyToken(String username, String password, String clientId, String clientSecret) {
		//选中认证服务的地址
		ServiceInstance serviceInstance = loadBalancerClient.choose(appName);
		if (serviceInstance == null) {
			throw new RRException("找不到对应的服务");
		}
		//获取令牌的url
		String path = serviceInstance.getUri().toString() + "/oauth/token";
		//定义body
		MultiValueMap<String, String> bodyData = new LinkedMultiValueMap<>();
		//授权方式
		bodyData.add("grant_type", GRANT_TYPE);
		//账号
		bodyData.add("username", username);
		//密码
		bodyData.add("password", password);

		//定义头
		MultiValueMap<String, String> header = new LinkedMultiValueMap<>();
		header.add("Authorization", httpBasic(clientId, clientSecret));

		//指定 restTemplate当遇到400或401响应时候也不要抛出异常，也要正常返回值 400 401无权限
		restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
			@Override
			public void handleError(ClientHttpResponse response) throws IOException {
				//当响应的值为400或401时候也要正常响应，不要抛出异常
				if (response.getRawStatusCode() != HttpStatus.BAD_REQUEST.value() && response.getRawStatusCode() != HttpStatus.UNAUTHORIZED.value()) {
					super.handleError(response);
				}
			}
		});
		AuthToken authToken;
		try {
			//http请求spring security的申请令牌接口
			ResponseEntity<AuthToken> mapResponseEntity = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(bodyData, header), AuthToken.class);
			//获取响应数据
			authToken = mapResponseEntity.getBody();
		} catch (RestClientException e) {
			throw new RRException("创建令牌失败！");
		}
		if (authToken == null || StrUtil.isEmpty(authToken.getAccess_token()) || StrUtil.isEmpty(authToken.getRefresh_token()) || StrUtil.isEmpty(authToken.getJti())) {
			//jti是jwt令牌的唯一标识作为用户身份令牌
			throw new RuntimeException("创建令牌失败！");
		}

		//返回响应数据AuthToken对象
		return authToken;
	}


	/***
	 * base64编码
	 */
	private String httpBasic(String clientId, String clientSecret) {
		//将客户端id和客户端密码拼接，按"客户端id:客户端密码"
		String string = clientId + ":" + clientSecret;
		//进行base64编码
		byte[] encode = Base64Utils.encode(string.getBytes());
		return "Basic " + new String(encode);
	}
}
